/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 *
 * Contains: Direct uart driver
 *
 * Change Logs:
 * Date           Author            Notes
 * 2022-4-17      JasonHu           Init
 * 2023-2-26      planck            Add interrupt trigger
 */

#include <nxos.h>
#include <drivers/direct_uart.h>
#include <drivers/gpio.h>
#include <base/console.h>
#include <base/log.h>
#include <base/debug.h>
#include <base/thread.h>

#include <sbi.h>
#include <regs.h>

void NX_HalDirectUartPutc(char ch)
{
    sbi_console_putchar(ch);
}

int NX_HalDirectUartGetc(void)
{
    if (!(Read32(UART0_LSR) & UART0_LSR_DR))
    {
        return -1;
    }
    return (int)Read32(UART0_RBR);
}

NX_INTERFACE void NX_ConsoleSendData(char ch)
{
    NX_HalDirectUartPutc(ch);
}

void NX_HalDirectUartInit(void)
{
    int addr;
    NX_U32 val;

    d1_set_gpio_mode(GPIO_PORT_B, GPIO_PIN_8, UART0_MODE_TX);
    d1_set_gpio_mode(GPIO_PORT_B, GPIO_PIN_9, UART0_MODE_RX);
   
    //设置串口时钟
    /* Open the clock gate for uart */
    val = Read32(D1_CCU_BASE + CCU_UART_BGR_REG);
    val |= 1 << (0);
    Write32(D1_CCU_BASE + CCU_UART_BGR_REG, val);

    /* Deassert uart reset */
    val = Read32(D1_CCU_BASE + CCU_UART_BGR_REG);
    val |= 1 << (16);
    Write32(D1_CCU_BASE + CCU_UART_BGR_REG, val);

    //配置串口功能
    /* Config uart0 to 115200-8-1-0 */
    addr = UART_BASE + 0 * 0x4000;
    Write32(addr + UART_DLH, 0x0);  // disable all interrupt
    Write32(addr + UART_FCR, 0xf7); // reset fifo
    Write32(addr + UART_MCR, 0x0);  // uart mode
    // set 115200
    val = Read32(addr + UART_LCR);
    val |= (1 << 7); // select Divisor Latch LS Register
    Write32(addr + UART_LCR, val);
    Write32(addr + UART_DLL, 0xd & 0xff);        // 0x0d=13 240000000/(13*16) = 115200 Divisor Latch Lows
    Write32(addr + UART_DLH, (0xd >> 8) & 0xff); // Divisor Latch High
    val = Read32(addr + UART_LCR);
    val &= ~(1 << 7);
    Write32(addr + UART_LCR, val);

    val = Read32(addr + UART_LCR);
    val &= ~0x1f;
    val |= (0x3 << 0) | (0 << 2) | (0x0 << 3); // 8 bit, 1 stop bit,parity disabled
    Write32(addr + UART_LCR, val);
    // enable uart rx irq
    Write32(addr + UART_IER, 0x01);
}

/**
 * default handler
 */
NX_WEAK_SYM void NX_HalDirectUartGetcHandler(char data)
{
    NX_ConsoleReceveData(data);
}

NX_PRIVATE NX_Error UartPollHandler(void)
{
    int data = NX_HalDirectUartGetc();
    if (data != -1)
    {
        if (NX_HalDirectUartGetcHandler != NX_NULL)
        {
            NX_HalDirectUartGetcHandler(data);
        }
    }
    return data != -1 ? NX_EOK : NX_EIO;
}


void NX_HalDirectUartStage2(void)
{
    NX_ASSERT(NX_IRQ_Bind(UART0_IRQ, UartPollHandler, NX_NULL, "Uart0", 0) == NX_EOK);
    NX_ASSERT(NX_IRQ_Unmask(UART0_IRQ) == NX_EOK);
}
